﻿//=======================================================
// Author: Jonas Follesø <jonas@follesoe.no>
// Copyright (c) 2008
//
// Licensed under the Microsoft Public License (Ms-PL)
// A copy of the license is available at 
// http://www.opensource.org/licenses/ms-pl.html
//=======================================================

using System;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using System.Windows.Media;
using System.Globalization;
using System.Collections.Generic;

using Colorful.Control.Properties;
using System.Xml;

namespace Colorful.Control.Services
{
    public class AdobeKuler : IGetColors
    {
        private readonly string apiBaseUrl = "http://kuler-api.adobe.com";
        private readonly string apiKey = "E471DF1DC2AF710EC81CA47012473CF7";

        private static IWebProxy Proxy
        {
            get
            {
                if (Settings.Default.UseDefaultProxy)
                    return WebRequest.DefaultWebProxy;
                
                if (string.IsNullOrEmpty(Settings.Default.ProxyAddress))
                    return null;
                
                return new WebProxy( Settings.Default.ProxyAddress, false, new string[0], CredentialCache.DefaultNetworkCredentials ); }
        }

        public string LogoTooltip { get { return "Colored by Adobe Kuler"; } }

        public System.Drawing.Bitmap Logo
        {
            get { return Resources.KulerBug36; }
        }
        
        public IEnumerable<ColorList> SupportedLists
        {
            get
            {
                yield return ColorList.Rating;
                yield return ColorList.Recent;
                yield return ColorList.Popular;
                yield return ColorList.Random;                                
                yield return ColorList.Search;
            }
        }

        public List<Palette> Search(string searchQuery, int startIndex, int itemsPerPage, out int totalItems)
        {   
            string requestUrlWithApiKey = string.Format("{0}/rss/search.cfm?searchQuery={1}&startIndex={2}&itemsPerPage={3}&key={4}", apiBaseUrl, searchQuery, startIndex * itemsPerPage, itemsPerPage, apiKey);
            string requestUrlWithoutApiKey = string.Format("{0}/rss/search.cfm?searchQuery={1}&startIndex={2}&itemsPerPage={3}", apiBaseUrl, searchQuery, startIndex * itemsPerPage, itemsPerPage);
            return DownloadColors(requestUrlWithApiKey, requestUrlWithoutApiKey, out totalItems);
        }

        public List<Palette> GetColors(ColorList list, int startIndex, int itemsPerPage, out int totalItems)
        {
            string requestUrlWithApiKey = string.Format("{0}/rss/get.cfm?listType={1}&startIndex={2}&itemsPerPage={3}&key={4}", apiBaseUrl, GetListName(list), startIndex * itemsPerPage, itemsPerPage, apiKey);
            string requestUrlWithoutApiKey =string.Format("{0}/rss/get.cfm?listType={1}&startIndex={2}&itemsPerPage={3}", apiBaseUrl, GetListName(list), startIndex * itemsPerPage, itemsPerPage, apiKey);
            return DownloadColors(requestUrlWithApiKey, requestUrlWithoutApiKey, out totalItems);
        }

        private List<Palette> DownloadColors(string requestUrlWithApiKey, string requestUrlWithoutApiKey, out int totalItems)
        {            
            try
            {
                return DownloadColors(requestUrlWithApiKey, out totalItems);
            }
            catch (XmlException)
            {
                return DownloadColors(requestUrlWithoutApiKey, out totalItems);
            }
        }

        /// <summary>Gets an <see cref="XmlReader"/> for the given <paramref name="url"/>, 
        /// using the static <see cref="IWebProxy"/> instance - <see cref="Proxy"/>.</summary>
        /// <param name="url">The Url to read.</param>
        /// <returns>An instance of an <see cref="XmlReader"/> with the given <paramref name="url"/> and proxy.</returns>
        private static XmlReader GetProxyXmlReader(string url)
        {
            var request = WebRequest.Create( url );
            request.Proxy = Proxy;

            var response = (HttpWebResponse) request.GetResponse();
            return XmlReader.Create( response.GetResponseStream());
        }

        private List<Palette> DownloadColors(string requestUrl, out int recordCount)
        {
            using (XmlReader reader = GetProxyXmlReader(requestUrl))
            {
                var document = XElement.Load( reader );
                var ns = document.GetNamespaceOfPrefix( "kuler" );

                recordCount = Convert.ToInt32( document.Element( "channel" ).Element( "recordCount" ).Value );

                var query = from theme in document.Element( "channel" )
                                .Elements( "item" )
                                .Elements( ns + "themeItem" )
                            select new Palette
                                       {
                                           Name = theme.Element( ns + "themeTitle" ).Value,
                                           Description = theme.Element( ns + "themeTags" ).Value,
                                           Author = theme.Element( ns + "themeAuthor" ).Element( ns + "authorLabel" ).Value,
                                           ThemeUrl = "http://kuler.adobe.com/#themeID/" + theme.Element( ns + "themeID" ).Value,
                                           Id = Convert.ToInt32( theme.Element( ns + "themeID" ).Value ),
                                           Rating = Convert.ToInt32( theme.Element( ns + "themeRating" ).Value ),
                                           Downloads = Convert.ToInt32( theme.Element( ns + "themeDownloadCount" ).Value ),
                                           CreatedAt = ToDate( theme.Element( ns + "themeCreatedAt" ).Value ),
                                           ColorList = from color in theme.Element( ns + "themeSwatches" ).Elements( ns + "swatch" )
                                                       select ToColor( color.Value )
                                       };

                return query.ToList();
            }
        }

        private Color ToColor(string hex)
        {
            return Color.FromArgb(255, 
                Convert.ToByte(hex.Substring(0, 2), 16), 
                Convert.ToByte(hex.Substring(2, 2), 16), 
                Convert.ToByte(hex.Substring(4, 2), 16));
        }

        public DateTime ToDate(string date)
        {
            return DateTime.ParseExact(date, "yyyyMMdd", CultureInfo.InvariantCulture);            
        }

        private string GetListName(ColorList list)
        {
            switch (list)
            {
                case ColorList.Popular:
                    return "popular";
                case ColorList.Rating:
                    return "rating";
                case ColorList.Random:
                    return "random";
                case ColorList.None:
                case ColorList.Recent:
                default:
                    return "recent";
            }
        }
    }
}
